#include "NetworkEventReceiver.h"

#include "SocketException.h"


using namespace std;



vector<HANDLE> vEvents;
vector<SOCKET> vSockets;
vector<OnCloseCallback> vCallbacks;


NetworkEventReceiver::NetworkEventReceiver() {	
	mNumSockets = 0;
	// create an event to interrupt WSAWaitForMultipleEvents
	// when a new socket was added
	mEvents[0] = CreateEvent(NULL, 0, 0, NULL);

	mNumSockets++;
}



void NetworkEventReceiver::run() {

	while (true) {
		DWORD index = WSAWaitForMultipleEvents(mNumSockets, mEvents, FALSE,  WSA_INFINITE, FALSE);

		switch(index) {
		case WSA_WAIT_FAILED: throw SocketException(_T("NetworkEventReceiver::run(): WSAWaitForMultipleEvents(): "),  WSAGetLastError());
		case WSA_WAIT_TIMEOUT: break;
		case WSA_WAIT_IO_COMPLETION: break;
		};

		index -= WSA_WAIT_EVENT_0;
	
		// index 0 is not a socket event
		if (index > 0) {
			
			WSANETWORKEVENTS events = {0};

			// reset the event for the socket and get information about all events that occured
			if (::WSAEnumNetworkEvents(mSockets[index], mEvents[index], &events) 
				== SOCKET_ERROR)  throw SocketException(_T("NetworkEventReceiver::run(): WSAEnumNetworkEvents(): "),  WSAGetLastError());

			// the error code for event FD_*  is at index FD_*_BIT of the iErrorCode array
			if (events.lNetworkEvents & FD_CLOSE) {
				
				printf("index: %u  ne %u  errc %u\n",index,events.lNetworkEvents, events.iErrorCode[FD_CLOSE_BIT]);
				printf("event is FD_CLOSE\n");

				switch(events.iErrorCode[FD_CLOSE_BIT]) {
				case NO_ERROR: break;
				case WSAENETDOWN: break;	//The network subsystem has failed.
				case WSAECONNRESET:	break;  //The connection was reset by the remote side.
				case WSAECONNABORTED: break;	//The connection was terminated due to a time-out or other failure.
				}

				// call the proper callback function and pass the associated socket
				mCallbacks[index](mSockets[index]);
			}
		} else {
			printf("event 0 signaled\n");
		}
	}
}


void NetworkEventReceiver::registerOnClose(SOCKET client, OnCloseCallback callback) {

	printf("registerOnClose\n");

	// Create a new event
	HANDLE newEvent;
	newEvent = WSACreateEvent();
	if (newEvent == WSA_INVALID_EVENT) 
		throw SocketException(_T("NetworkEventReceiver::registerOnClose(): WSACreateEvent(): "),  WSAGetLastError());

	
	// Associate event type FD_CLOSE
	// with the socket and NewEvent
	if (::WSAEventSelect(client, newEvent, FD_CLOSE)
		== SOCKET_ERROR) throw SocketException(_T("NetworkEventReceiver::registerOnClose(): WSAEventSelect(): "),  WSAGetLastError());


	mSockets[mNumSockets] = client;
	mCallbacks[mNumSockets] = callback;
	mEvents[mNumSockets]  = newEvent;
	mNumSockets++;

	// signal event 0 to  interrupt WSAWaitForMultipleEvents
	SetEvent(mEvents[0]);
}